package com.joymart.order.service;


import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.dictionary.Dictionary;
import com.joymart.dictionary.DictionaryService;
import com.joymart.order.model.Order;
import com.joymart.product.model.Product;
import com.joymart.product.service.ProductService;
import com.joymart.user.model.User;
import com.joymart.user.repo.UserRepository;
import com.joymart.user.service.UserCacheManager;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import com.joymart.common.model.Range;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import static com.joymart.common.utils.CollectionUtils.asList;
import static com.joymart.common.utils.CollectionUtils.asStream;
import static com.joymart.common.utils.SecurityUtils.checkCurrentUserIsAny;
import static org.springframework.data.relational.core.query.Criteria.where;
import static org.springframework.data.relational.core.query.Query.query;

@Service
public class OrderQueryService {


    @Autowired
    private JdbcAggregateTemplate jdbcAggregateTemplate;
    @Autowired
    private OrderService orderService;
    @Autowired
    private ProductService productService;
    @Autowired
    private UserRepository userRepository;
    private User headQuarter;


    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private DictionaryService dictionaryService;

    @PostConstruct
    public void init() {
        headQuarter = userRepository.findById("10000").get();
    }


    public OrderDTO findById(String orderId) {
        Order order = orderService.getById(orderId);
        checkCurrentUserIsAny(order::getBuyerId, order::getFirstSellerId, order::getSecondSellerId);
        return toOrderDTO(order);
    }

    public Page<OrderAdminDTO> searchAdminOrders(
            Range range,
            String orderId,
            String receiver,
            Pageable pageable, Order.Status... status
    ) {
        LocalDateTime start = range.getStart();
        LocalDateTime end = range.getEnd();
        Criteria criteria =   where("createdAt").between(start, end);
        if(status.length > 0){
            criteria = criteria.and(where("status").in(status));
        }
        if(StringUtils.hasText(orderId)){
            criteria = criteria.and(where("id").is(orderId));
        }
        if(StringUtils.hasText(receiver)){
            criteria = criteria.and(where("receiverName").like("%"+receiver+"%"));
        }

        long count = jdbcAggregateTemplate.count(query(criteria), Order.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<Order> content = asList(jdbcAggregateTemplate.findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                    .sort(Sort.by(Sort.Direction.DESC, "createdAt")), Order.class));
            return new PageImpl<>(content,pageable , count).map(this::toOrderAdminDTO);
        }
    }



    public Page<OrderDTO> searchCustomerOrders(Range range,
                                               String receiver, String orderId, Pageable pageable, Order.Status... status) {
        LocalDateTime start = range.getStart();
        LocalDateTime end = range.getEnd();
        Criteria criteria =
                where("buyerId").is(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
                        .and(where("createdAt").between(start, end));
        if(status.length > 0){
            criteria = criteria.and(where("status").in(status));
        }
        if(StringUtils.hasText(orderId)){
            criteria = criteria.and(where("id").is(orderId));
        }
        if(StringUtils.hasText(receiver)){
            criteria = criteria.and(where("receiverName").like("%"+receiver+"%"));
        }
        long count = jdbcAggregateTemplate.count(query(criteria), Order.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<Order> content = asList(jdbcAggregateTemplate.findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                    .sort(Sort.by(Sort.Direction.DESC, "createdAt")), Order.class));
            return new PageImpl<>(content,pageable , count).map(this::toOrderDTO);
        }
    }

    public Page<OrderDTO> searchShopOrders(Range range,
                                           String orderId,
                                           String category,
                                           String receiver,
                                           Pageable pageable) {
        LocalDateTime start = range.getStart();
        LocalDateTime end = range.getEnd();
        String currentUserId = SecurityUtils.getCurrentUserId();
        List<Criteria> conditions = new ArrayList<>();
        conditions.add(where("createdAt").between(start, end));
        if (StringUtils.hasText(orderId)) {
            conditions.add(where("id").is(orderId));
        }

        if (StringUtils.hasText(receiver)) {
            conditions.add(where("receiverName").like("%" + receiver + "%"));
        }

        //其他写法优先级可能不对
        Criteria criteria = where("firstSellerId").is(currentUserId).and(conditions)
                .or(where("secondSellerId").is(currentUserId).and(conditions));

        Query query = query(criteria).sort(Sort.by(Sort.Direction.DESC, "createdAt"));
        Stream<Order> orders = asStream(jdbcAggregateTemplate.findAll(query, Order.class));

        if (List.of(Order.Status.SECOND_SELLER_PAID.name(),
                        Order.Status.DELIVERING.name(),
                        Order.Status.RECEIVED.name())
                .contains(category)) {
            orders = orders.filter(order -> order.getStatus() == Order.Status.valueOf(category));
        }

        if (category.equals("NEED_CONFIRMATION")) {
            orders = orders.filter(
                    order -> needConfirmation(order, currentUserId)
            );
        }

        if (category.equals("CONFIRMED")) {
            orders = orders.filter(
                    order -> alreadyConfirmed(order, currentUserId)
            );
        }
        List<Order> list = orders.toList();
        return new PageImpl<>(list.stream().skip(pageable.getOffset()).limit(pageable.getPageSize()).toList(),
                pageable, list.size()).map(this::toOrderDTO);

    }


    public boolean alreadyConfirmed(Order order, String userId) {
        return (order.getStatus() == Order.Status.BUYER_PAID && order.getFirstSellerId().equals(userId)) //第一卖家确认过收款
                || (order.getStatus() == Order.Status.FIRST_SELLER_PAID && order.getSecondSellerId().equals(userId)); //第二买家确认过收款
    }

    public boolean needConfirmation(Order order, String userId) {
        return (order.getStatus() == Order.Status.CREATED && order.getFirstSellerId().equals(userId)) || //待第一卖家确认
                (order.getStatus() == Order.Status.BUYER_PAID && order.getSecondSellerId().equals(userId));//待第二卖家确认
    }


    public OrderDTO toOrderDTO(Order order) {
        String userId = SecurityUtils.getCurrentUserId();

        OrderDTO orderDto = new OrderDTO();
        BeanUtils.copyProperties(order, orderDto);
        if(StringUtils.hasText(order.getDeliveryVendorId())){
            Dictionary vendorsDictionary = dictionaryService.findByName("deliveryVendors");
            String deliveryVendorName = vendorsDictionary.getItemText(orderDto.getDeliveryVendorId());
            orderDto.setDeliveryVendorName(deliveryVendorName);
        }

        orderDto.setHeadQuarter(headQuarter);
        orderDto.setBuyer(userCacheManager.get(order.getBuyerId()).getUser());
        orderDto.setFirstSeller(userCacheManager.get(order.getFirstSellerId()).getUser());
        orderDto.setSecondSeller(userCacheManager.get(order.getSecondSellerId()).getUser());
        Product product = productService.findByIdFromCache(order.getProductId());
        orderDto.setProductName(product.getName());
        orderDto.setProductMeta(product.getMeta());
        completeActionsAndInstruction(orderDto, order, userId);
        return orderDto;
    }

    private void completeActionsAndInstruction(OrderDTO dto, Order order, String userId) {

        List<String> actions = new ArrayList<>();

        if (order.getStatus() == Order.Status.CREATED && order.getBuyerId().equals(userId)) {
            actions.add("CANCEL");
            dto.setInstruction("请缴纳货款¥[%s]元".formatted(order.getTotalPrice()));
            dto.setInstructionUser(dto.getFirstSeller());
            if(!order.isFirstSellerInformed()){
                actions.add("INFORM_FIRST_SELLER");
            }
        }

        if (order.getStatus() == Order.Status.CREATED && order.getFirstSellerId().equals(userId)) {
            actions.add("CONFIRM_BUYER_PAID");
            dto.setInstruction("请等待买家[%s]支付货款¥[%s]元。如已经支付，请及时确认".formatted(dto.getBuyer().getNickname(), order.getTotalPrice()));
            dto.setInstructionUser(dto.getBuyer());
            if(order.isFirstSellerInformed()){
                dto.setHighlighted(true);
            }
        }


        if (order.getStatus() == Order.Status.BUYER_PAID && order.getFirstSellerId().equals(userId)) {
            dto.setInstruction("请缴纳货款¥[%s]元".formatted(order.getTotalPrice().subtract(
                    order.getFirstSellerProfit(),
                    MathContext.DECIMAL64)));
            dto.setInstructionUser(dto.getSecondSeller());
            if(!order.isSecondSellerInformed()){
                actions.add("INFORM_SECOND_SELLER");
            }
        }

        if (order.getStatus() == Order.Status.BUYER_PAID && order.getSecondSellerId().equals(userId)) {
            actions.add("CONFIRM_FIRST_SELLER_PAID");

            dto.setInstruction("请等待下级店铺[%s]支付货款¥[%s]元。如已经支付，请及时确认".formatted(dto.getFirstSeller().getNickname(), order.getTotalPrice().subtract(
                    order.getFirstSellerProfit(), MathContext.DECIMAL64
            )));

            if(order.isSecondSellerInformed()){
                dto.setHighlighted(true);
            }
        }

        if (order.getStatus() == Order.Status.FIRST_SELLER_PAID && order.getSecondSellerId().equals(userId)) {
//            actions.add("INFORM_HEAD_QUARTER");

            dto.setInstruction("请缴纳货款¥[%s]元".formatted(order.getTotalPrice().subtract(order.getFirstSellerProfit(), MathContext.DECIMAL64)
                    .subtract(order.getSecondSellerProfit(), MathContext.DECIMAL64)));
            dto.setInstructionUser(dto.getHeadQuarter());
        }

        if (order.getStatus() == Order.Status.DELIVERING && order.getBuyerId().equals(userId)) {
            actions.add("RECEIVE");
        }
        if (order.getStatus() == Order.Status.RECEIVED && order.getBuyerId().equals(userId)) {
            actions.add("REFUND");
        }

        dto.setActions(actions);
    }


    @Data
    public static class OrderDTO {

        private String id;
        private Order.Status status;
        private String productId;
        private String productName;
        @JsonSerialize
        private JSONObject productMeta;
        private Integer quantity;
        private BigDecimal unitPrice;
        private BigDecimal unitPv;
        private BigDecimal totalPrice;
        private BigDecimal totalPv;
        private User buyer;
        private User firstSeller;
        private BigDecimal firstSellerProfit;
        private User secondSeller;
        private BigDecimal secondSellerProfit;
        @JsonIgnore
        private User headQuarter;
        private String receiverName;
        private String receiverPhone;
        private String receiverDistrict;
        private String receiverAddress;
        private String deliveryVendorName;
        private String deliveryVendorId;
        private String deliveryNo;
        private String remark;
        private LocalDateTime createdAt;
        private List<String> actions;
        private String instruction;
        private User instructionUser;
        private boolean highlighted;
        /**
         * 计算总部收款金额
         * @return
         */
        public BigDecimal getHeadQuarterPrice() {
            return  this.getTotalPrice().subtract(this.getFirstSellerProfit(), MathContext.DECIMAL64)
                    .subtract(this.getSecondSellerProfit(), MathContext.DECIMAL64);
        }
    }


    public OrderAdminDTO toOrderAdminDTO(Order order) {

        OrderAdminDTO orderAdminDTO = new OrderAdminDTO();
        BeanUtils.copyProperties(order, orderAdminDTO);
        orderAdminDTO.setBuyer(userCacheManager.get(order.getBuyerId()).getUser());
        orderAdminDTO.setFirstSeller(userCacheManager.get(order.getFirstSellerId()).getUser());
        orderAdminDTO.setSecondSeller(userCacheManager.get(order.getSecondSellerId()).getUser());
        Product product = productService.findByIdFromCache(order.getProductId());
        orderAdminDTO.setProductName(product.getName());
        orderAdminDTO.setProductMeta(product.getMeta());
        List<String> actions = new ArrayList<>();
        if(order.getStatus()== Order.Status.FIRST_SELLER_PAID){
            actions.add("CONFIRM_SECOND_SELLER_PAID");
        }
        if(order.getStatus()  == Order.Status.SECOND_SELLER_PAID){
            actions.add("MAKE_DELIVERY");
        }
        orderAdminDTO.setActions(actions);
        return orderAdminDTO;
    }
    @Data
    public static class OrderAdminDTO {

        private String id;
        private Order.Status status;
        private String productId;
        private String productName;
        @JsonSerialize
        private JSONObject productMeta;
        private Integer quantity;
        private BigDecimal unitPrice;
        private BigDecimal unitPv;
        private BigDecimal totalPrice;
        private BigDecimal totalPv;
        private User buyer;
        private User firstSeller;
        private BigDecimal firstSellerProfit;
        private User secondSeller;
        private BigDecimal secondSellerProfit;
        private String receiverName;
        private String receiverPhone;
        private String receiverDistrict;
        private String receiverAddress;
        private String deliveryVendorId;
        private String deliveryNo;
        private String remark;
        private LocalDateTime createdAt;
        private List<String> actions;

        /**
         * 计算总部收款金额
         * @return
         */
        public BigDecimal getHeadQuarterPrice() {
          return  this.getTotalPrice().subtract(this.getFirstSellerProfit(), MathContext.DECIMAL64)
                    .subtract(this.getSecondSellerProfit(), MathContext.DECIMAL64);
        }
    }




}
